<?php
/** 
*
* @author Benjamin Stassart
*
* @package acp
* @version $Id: acp_applys.php 5 2011-01-29 21:36:22Z benstassart@gmail.com $
* @copyright (c) 2010-2011 Benjamin Stassart
* @license http://opensource.org/licenses/gpl-license.php GNU Public License 
*
*/

/**
* acp_applys
* Application MOD
* @package acp
*/
class acp_applys
{
	var $NUM_QTYPES = '16';
	var $DEFAULT_TYPE = '3';
	var $DEFAULT_QUESTION = 'Question';
	var $DEFAULT_REQUIRED = '0';
	var $u_action;
	var $new_applys_config = array();
	var $applys_config = array();
	var $applys_questions = array();
	var $questions_loaded = 0;

	function main($id, $mode)
	{
		global $config, $db, $user, $auth, $template;
		global $phpbb_root_path, $phpbb_admin_path, $phpEx;

		// $user->add_lang(array('posting', 'ucp', 'acp/users'));
		// This isn't needed
		// $user->add_lang('mods/info_acp_applys_mod');
		$user->add_lang('acp/permissions');

		// validate data
		include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
		// version number
		include($phpbb_root_path . 'includes/acp/info/acp_applys.' . $phpEx);
		
		$action 	= request_var('action', '');
		$submit		= (isset($_POST['submit'])) ? true : false;
		$addq 		= (isset($_POST['add'])) ? true : false;
		$delete 	= (isset($_POST['delete'])) ? true : false;
		$moveup 	= (isset($_POST['moveup'])) ? true : false;
		$movedown 	= (isset($_POST['movedown'])) ? true : false;

		$any_submit	= ($submit || $addq || $delete || $moveup || $movedown) ? true : false;

		$delete_ary	= ($delete) ? request_var('delete', array('' => ''), true) : array();
		$moveup_ary	= ($moveup) ? request_var('moveup', array('' => ''), true) : array();
		$movedown_ary	= ($movedown) ? request_var('movedown', array('' => ''), true) : array();

		// Check version
		$version = new acp_applys_info();
		
		$applys_version = $version->module();
		$applys_version = $applys_version['version'];
		
		if (!isset($config['applys_version']))
		{
			$version->install();
		}
		else if (version_compare($config['applys_version'], $applys_version, '<'))
		{
			$version->update();
		}

		// Get configuration here
		$this->load_applys_config();
		// Do not provide current password
		$this->obscure_password();
		// Set anything missing to the defaults
		$this->default_applys_config();
		// Load questions
		$this->load_questions();

		$form_key = 'acp_applys';
		add_form_key($form_key);

		/**
		*	Validation types are:
		*		string, int, bool,
		*		script_path (absolute path in url - beginning with / and no trailing slash),
		*		rpath (relative), rwpath (realtive, writable), path (relative path, but able to escape the root), wpath (writable)
		*/
		$display_vars = array(
				'title' => 'APPLYS',
				'vars' => array(
					'legend1'		=> 'ACP_APPLYS_CONFIGURATION',
					'guildname'		=> array('lang' => 'APPLYS_GUILDNAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false),
					'faction'		=> array('lang' => 'APPLYS_FACTION', 'validate' => 'string', 'type' => 'select', 'method' => 'select_faction', 'explain' => false),
					'region'		=> array('lang' => 'APPLYS_REGION', 'validate' => 'string', 'type' => 'select', 'method' => 'select_region', 'explain' => false),
					'realm'			=> array('lang' => 'APPLYS_REALM', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false),
					'require_login'		=> array('lang' => 'APPLYS_REQUIRE_LOGIN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
					'app_user'		=> array('lang' => 'APPLYS_USER', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_user', 'explain' => true),
					'app_pass'		=> array('lang' => 'APPLYS_PASS', 'validate' => 'string', 'type' => 'password:40:255', 'explain' => true), 
					'forum_id'		=> array('lang' => 'APPLYS_FORUM_ID', 'validate' => 'int', 'type' => 'select', 'method' => 'select_forum', 'explain' => true), 
					'sec_forum'		=> array('lang' => 'APPLYS_SEC_FORUM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
					'sec_forum_id'		=> array('lang' => 'APPLYS_SEC_FORUM_ID', 'validate' => 'int', 'type' => 'select', 'method' => 'select_forum', 'explain' => true), 
					'sec_forum_poll'	=> array('lang' => 'APPLYS_SEC_FORUM_POLL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),

					'legend2'		=> 'APPLYS_QUESTIONS',
				)
			);

		$question_id = 0;
		if (isset($this->applys_config['first_question_id'])) {
			$question_id = $this->applys_config['first_question_id'];
		}
		while ($question_id > 0)
		{
			$question = $this->applys_questions[$question_id];

			$question_string = "question" . $question_id;
			$this->applys_config[$question_string] = $question['question'];
			$display_vars['vars'][$question_string] = array('lang' => 'APPLYS_Q', 'validate' => 'string', 'type' => 'text:100:255', 'explain' => false);
			$question_type= "question_type" . $question_id;

			$this->applys_config[$question_type] = $question['type'];
			$display_vars['vars'][$question_type] = array('lang' => 'APPLYS_QTYPE', 'validate' => 'int', 'type' => 'select', 'method' => 'select_qtype', 'explain' => false);

			$question_required = "question_required" . $question_id;
			$this->applys_config[$question_required] = $question['required'];
			$display_vars['vars'][$question_required] = array('lang' => 'APPLYS_REQUIRED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false);

			$question_control = "question_control" . $question_id;
			$display_vars['vars'][$question_control] = array('lang' => 'APPLYS_CONTROL', 'type' => 'custom', 'method' => 'select_control', 'explain' => false);

			$question_id = $question['right_id'];
		}

		$display_vars['vars']['legend3'] = 'ACP_SUBMIT_CHANGES';

		if (isset($display_vars['lang']))
		{
			$user->add_lang($display_vars['lang']);
		}

		$this->new_applys_config = $this->applys_config;
		// build_cfg_template is hardcoded to use config as the prefix for the values
		$cfg_array = (isset($_REQUEST['config'])) ? utf8_normalize_nfc(request_var('config', array('' => ''), true)) : $this->new_applys_config;
		$error = array();

		// We validate the complete config if whished
		validate_config_vars($display_vars['vars'], $cfg_array, $error);

		// If we do not require login, app_user must be a valid user and password
		$user_id_ary = array();
		if ($submit && !$cfg_array['require_login'])
		{
			if (isset($cfg_array['app_user']) and ($cfg_array['app_user']))
			{
				$username_ary = array($cfg_array['app_user']);
				user_get_id_name($user_id_ary, $username_ary);
			}
			else
			{
				trigger_error($user->lang['APPLYS_NO_USER'] . adm_back_link($this->u_action), E_USER_WARNING);
			}

			if (!sizeof($user_id_ary))
		 	{
				trigger_error($user->lang['SELECTED_USER_NOT_EXIST'] . adm_back_link($this->u_action), E_USER_WARNING);
			}

			// Check password
			if (!isset($cfg_array['app_pass']) or (!$cfg_array['app_pass']))
			{
				trigger_error($user->lang['NO_PASSWORD_SUPPLIED'] . adm_back_link($this->u_action), E_USER_WARNING);
			}

			// Don't check the password if it is just an obscured one as the real one isn't supplied to the user
			// Just check it if they provide a new password
			if (!$this->is_obscure($cfg_array['app_pass']) and
			    !$this->check_password($user_id_ary[0], $cfg_array['app_pass']))
			{
				trigger_error($user->lang['APPLYS_INVALID_PASS'] . adm_back_link($this->u_action), E_USER_WARNING);
			}
		}


		// Try to automatically determine the timezone and daylight savings time settings
		$timezone = date('Z') / 3600;
		$is_dst = date('I');

		if ($config['board_timezone'] == $timezone || $config['board_timezone'] == ($timezone - 1))
		{
			$timezone = ($is_dst) ? $timezone - 1 : $timezone;

			if (!isset($user->lang['tz_zones'][(string) $timezone]))
			{
				$timezone = $config['board_timezone'];
			}
		}
		else
		{
			$is_dst = $config['board_dst'];
			$timezone = $config['board_timezone'];
		}
		
		$data = array(
			'guildname'		=> utf8_normalize_nfc(request_var('guildname', '', true)),
		);
		
		// Check if the form was valid
		if ($submit && !check_form_key($form_key))
		{
			$error[] = $user->lang['FORM_INVALID'];
		}
		// Do not write values if there is an error
		if (sizeof($error))
		{
			$submit = false;
		}

		// We go through the display_vars to make sure no one is trying to set variables he/she is not allowed to...
		foreach ($display_vars['vars'] as $config_name => $null)
		{
			if (!isset($cfg_array[$config_name]) || strpos($config_name, 'legend') !== false)
			{
				continue;
			}

			// if ($config_name == 'auth_method' || $config_name == 'feed_news_id' || $config_name == 'feed_exclude_id')
			// {
			// 	continue;
			// }

			$this->new_applys_config[$config_name] = $config_value = $cfg_array[$config_name];

			if ($any_submit)
			{
				if (strpos($config_name, 'question') === false)
				{
					// Do not write obscure password to the config database
					if (($config_name != 'app_pass') || !$this->is_obscure($config_value))
					{
						// Don't put the questions in the config database
						// Update applys database here
						$this->set_applys_config($config_name, $config_value);
					}
				}
				else
				{
					// Update the questions array
					if (strpos($config_name, 'question_type') !== false)
					{
						if (preg_match('/question_type(\d+)/', $config_name, $matches)) {
							$this->applys_questions[$matches[1]]['type'] = $config_value;
						}
						else
						{
							trigger_error($user->lang['APPLYS_QTYPE'] . ' regex fail');
						}
					}
					else if (strpos($config_name, 'question_required') !== false)
					{
						if (preg_match('/question_required(\d+)/', $config_name, $matches)) {
							$this->applys_questions[$matches[1]]['required'] = $config_value;
						}
						else
						{
							trigger_error($user->lang['APPLYS_REQUIRED'] . ' regex fail');
						}
					}
					else if (strpos($config_name, 'question_control') !== false)
					{
						// Ignored
					}
					else // Question
					{
						if (preg_match('/question(\d+)/', $config_name, $matches)) {
							$this->applys_questions[$matches[1]]['question'] = $config_value;
						}
						else
						{
							trigger_error($user->lang['APPLYS_Q'] . ' regex fail');
						}
					}
				}
			}
		}

		if ($any_submit)
		{
			// Update the questions database
			$errors = $this->update_questions();

			if ($errors)
			{
				trigger_error($user->lang['APPLYS_QERRORS'] . adm_back_link($this->u_action));
			}
		}

		if ($submit)
		{
			add_log('admin', 'LOG_CONFIG_' . strtoupper($mode));
			$this->set_applys_config("configured", 1);

			trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
		}

		// Add the question and redirect
		if ($addq)
		{
			$this->add_question();
			redirect($this->u_action);
		}

		// Delete the question and redirect
		if ($delete)
		{
			foreach ($delete_ary as $key => $value) {
				// trigger_error("Delete key:" . $key . ", value: ". $value);
				$this->delete_question($key);
			}
			redirect($this->u_action);
		}

		// Move up the question
		if ($moveup)
		{
			foreach ($moveup_ary as $key => $value) {
				// trigger_error("Delete key:" . $key . ", value: ". $value);
				$this->moveup_question($key);
			}
			redirect($this->u_action);
		}

		// Move down the question
		if ($movedown)
		{
			foreach ($movedown_ary as $key => $value) {
				// trigger_error("Delete key:" . $key . ", value: ". $value);
				$this->movedown_question($key);
			}
			redirect($this->u_action);
		}

		$this->tpl_name = 'acp_applys';
		$this->page_title = $display_vars['title'];
		
		$template->assign_vars(array(
			'L_TITLE'			=> $user->lang[$display_vars['title']],
			'L_TITLE_EXPLAIN'	=> $user->lang[$display_vars['title'] . '_EXPLAIN'],

			'S_ERROR'			=> (sizeof($error)) ? true : false,
			'ERROR_MSG'			=> implode('<br />', $error),

			'U_ACTION'			=> $this->u_action)
		);

		// Output relevant page
		foreach ($display_vars['vars'] as $config_key => $vars)
		{
			if (!is_array($vars) && strpos($config_key, 'legend') === false)
			{
				// Not an array or a legend, skip it
				continue;
			}

			if (strpos($config_key, 'legend') !== false)
			{
				// Legend
				$template->assign_block_vars('options', array(
					'S_LEGEND'		=> true,
					'LEGEND'		=> (isset($user->lang[$vars])) ? $user->lang[$vars] : $vars)
				);

				continue;
			}

			$type = explode(':', $vars['type']);

			$l_explain = '';
			if ($vars['explain'] && isset($vars['lang_explain']))
			{
				$l_explain = (isset($user->lang[$vars['lang_explain']])) ? $user->lang[$vars['lang_explain']] : $vars['lang_explain'];
			}
			else if ($vars['explain'])
			{
				$l_explain = (isset($user->lang[$vars['lang'] . '_EXPLAIN'])) ? $user->lang[$vars['lang'] . '_EXPLAIN'] : '';
			}

			$content = build_cfg_template($type, $config_key, $this->new_applys_config, $config_key, $vars);

			if (empty($content))
			{
				continue;
			}

			$template->assign_block_vars('options', array(
				'KEY'			=> $config_key,
				'TITLE'			=> (isset($user->lang[$vars['lang']])) ? $user->lang[$vars['lang']] : $vars['lang'],
				'S_EXPLAIN'		=> $vars['explain'],
				'TITLE_EXPLAIN'	=> $l_explain,
				'CONTENT'		=> $content,
				)
			);
			unset($display_vars['vars'][$config_key]);
		}

		$template->assign_vars(array(
			'L_ADD_QUESTION'	=> (isset($user->lang['APPLYS_ADDQ'])) ? $user->lang['APPLYS_ADDQ'] : 'APPLYS_ADDQ',
			)
		);
	}

	/**
	* Loading the applys_config
	*/
	function load_applys_config()
	{
		global $db;

		// When addons are installed, before the install script is run, this would through an error.
		$db->sql_return_on_error(true);
		$sql = 'SELECT *
			FROM ' . APPLYS_CONFIG_TABLE;
		$result = $db->sql_query($sql);
		$db->sql_return_on_error(false);

		$this->applys_config = array();
		if ($result !== false)
		{
			$this->applys_config['loaded'] = true;
		}

		while ($row = $db->sql_fetchrow($result))
		{
			$this->applys_config[$row['config_name']] = $row['config_value'];
		}
		$db->sql_freeresult($result);

		// return $applys_config;
	}

	/**
	* Obscure the password
	* Every if you use an HTML password field, the HTML source still shows the password
	* I don't want to provide the password to everyone who has access to change the form
	*/
	function obscure_password()
	{
		if (isset($this->applys_config['app_pass']) and ($this->applys_config['app_pass']))
		{
			// No reason to show the user the real length even
			// $pass_len = strlen($this->applys_config['app_pass']);
			$this->applys_config['app_pass'] = str_repeat("*", 10);
		}
	}

	/**
	* Is the string an obscured password?
	*/
	function is_obscure($str)
	{
		if (preg_match('/^[*]+$/', $str))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/**
	* Set config value. Creates missing applys_config entry.
	*
	* borrowed from phpBB3
	* @author: phpBB Group
	* @function: set_applys_config
	*/
	function set_applys_config($config_name, $config_value, $is_dynamic = false)
	{
		global $db /*, $cache*/;

		if (!isset($this->applys_config['loaded']))
		{
			trigger_error('set_applys_config called without loading configuration first.');
		}

		$sql = 'UPDATE ' . APPLYS_CONFIG_TABLE . "
			SET config_value = '" . $db->sql_escape($config_value) . "'
			WHERE config_name = '" . $db->sql_escape($config_name) . "'";
		$db->sql_query($sql);

		if (!$db->sql_affectedrows() && !isset($this->applys_config[$config_name]))
		{
			$sql = 'INSERT INTO ' . APPLYS_CONFIG_TABLE . ' ' . $db->sql_build_array('INSERT', array(
				'config_name'	=> $config_name,
				'config_value'	=> $config_value,
				/*'is_dynamic'	=> ($is_dynamic) ? 1 : 0,*/));
			$db->sql_query($sql);
		}

		$this->applys_config[$config_name] = $config_value;

		/*if (!$is_dynamic)
		{
			$cache->destroy('config');
		}*/
	}

	/**
	* Set any missing configuration options to defaults
	*/
	function default_applys_config()
	{
		global $config;

		if (!isset($this->applys_config['guildname']))
		{
			$this->set_applys_config('guildname', $config['sitename']);
		}
		if (!isset($this->applys_config['faction']))
		{
			$this->set_applys_config('faction', 'APPLYS_HORDE');
		}
		if (!isset($this->applys_config['region']))
		{
			$this->set_applys_config('region', 'US');
		}
		if (!isset($this->applys_config['require_login']))
		{
			$this->set_applys_config('require_login', 0);
		}
		if (!isset($this->applys_config['forum_id']))
		{
			$this->set_applys_config('forum_id', 2);
		}
		if (!isset($this->applys_config['sec_forum']))
		{
			$this->set_applys_config('sec_forum', 0);
		}
		if (!isset($this->applys_config['sec_forum_id']))
		{
			$this->set_applys_config('sec_forum_id', 2);
		}
		if (!isset($this->applys_config['sec_forum_poll']))
		{
			$this->set_applys_config('sec_forum_poll', 1);
		}
	}

	/**
	* Loading the applys_questions
	*/
	function load_questions()
	{
		global $db;

		// When addons are installed, before the install script is run, this would through an error.
		$db->sql_return_on_error(true);
		$sql = 'SELECT *
			FROM ' . APPLYS_QUESTIONS_TABLE;
			
		$result = $db->sql_query($sql);
		$db->sql_return_on_error(false);

		$this->applys_questions = array();

		while ($row = $db->sql_fetchrow($result))
		{
			$this->applys_questions[$row['question_id']] = array(
				'left_id' => $row['left_id'],
				'right_id' => $row['right_id'],
				'question' => $row['question'],
				'type' => $row['type'],
				'required' => $row['required'],
				);
		}
		$db->sql_freeresult($result);
		$this->questions_loaded = 1;
	}

	/**
	* Update applys_questsion
	*/
	function update_questions()
	{
		global $db;
		$errors = 0;

		if (!sizeof($this->applys_questions))
		{
			return $errors;
		}

		if (!$this->questions_loaded)
		{
			trigger_error('Update questions called without loading questions first.');
		}

		// foreach ($this->applys_questions as $qid => $q)
		// {

		$qid = 0;
		if (isset($this->applys_config['first_question_id'])) {
			$qid = $this->applys_config['first_question_id'];
		}
		while ($qid > 0)
		{
			$q = $this->applys_questions[$qid];
			$left_id = $q['left_id'];
			$right_id = $q['right_id'];
			$question = $q['question'];
			$type = $q['type'];
			$required = $q['required'];

			// question_id is intentionally wrong here atm
			if (!isset($qid) || !isset($question) ||
				!isset($type) || !isset($required) ||
				!isset($left_id) || !isset($right_id))
			{
				$errors += 1;
				trigger_error('qid:'.$qid.',lid:'.$left_id.',rid:'.$right_id.',q:'.$question.',t:'.$type.',req:'.$required);
				continue;
			}

			$db->sql_return_on_error(true);
			$sql = 'UPDATE ' . APPLYS_QUESTIONS_TABLE . "
				SET left_id = '" . (int)$left_id . "',
				right_id = '" . (int)$right_id . "',
				question = '" . $db->sql_escape($question) . "',
				type = '" . (int)$type . "',
				required = '" . (int)$required . "'
				WHERE question_id = '" . (int)$qid . "'";

			$result = $db->sql_query($sql);
			$db->sql_return_on_error(false);
			$db->sql_freeresult($result);

			$qid = $right_id;
		}
		return $errors;
	}

	/**
	* Add question to database
	* This does not update $this->applys_questions
	*/
	function add_question()
	{
		global $db;

		$left_id = 0;
		$right_id = 0;

		$sql_ary = array();
		$sql_ary['left_id'] = $left_id;
		$sql_ary['right_id'] = $right_id;
		$sql_ary['type'] = $this->DEFAULT_TYPE;
		$sql_ary['question'] = $this->DEFAULT_QUESTION;
		$sql_ary['required'] = $this->DEFAULT_REQUIRED;

		if (!isset($this->applys_config['loaded']))
		{
			trigger_error('add_question called without loading configuration first.');
		}
		if (!$this->questions_loaded)
		{
			trigger_error('add_question called without loading questions first.');
		}

		if (!isset($this->applys_config['first_question_id']) &&
		    !isset($this->applys_config['last_question_id']))
		{
			$db->sql_return_on_error(true);
			$sql = 'INSERT INTO ' . APPLYS_QUESTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);

			$result = $db->sql_query($sql);
			$question_id = $db->sql_nextid();

			$db->sql_return_on_error(false);
			$db->sql_freeresult($result);

			// First question
			$this->set_applys_config('first_question_id', $question_id);
			$this->set_applys_config('last_question_id', $question_id);
		}
		else {
			$left_id = $this->applys_config['last_question_id'];
			$sql_ary['left_id'] = $left_id;

			$db->sql_return_on_error(true);
			$sql = 'INSERT INTO ' . APPLYS_QUESTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary);
			$result = $db->sql_query($sql);
			$question_id = $db->sql_nextid();

			$db->sql_freeresult($result);
			$db->sql_return_on_error(false);

			// Update the right pointer in the previous question
			$db->sql_return_on_error(true);
			$sql = 'UPDATE ' . APPLYS_QUESTIONS_TABLE . "
				SET right_id = '" . (int)$question_id . "'
				WHERE question_id = '" . (int)$left_id . "'";
			$result = $db->sql_query($sql);

			$db->sql_freeresult($result);
			$db->sql_return_on_error(false);

			$this->set_applys_config('last_question_id', $question_id);
		}
	}

	/**
	* Delete question from database
	* This does not update $this->applys_questions
	* qid = question_id
	*/
	function delete_question($qid)
	{
		global $db;

		if (!$qid)
		{
			trigger_error("Invalid question_id to delete_question");
		}

		if (!isset($this->applys_questions[$qid]))
		{
			trigger_error("Call to delete_question with non-existent question.");
		}

		$q = $this->applys_questions[$qid];
		$left_id = $q['left_id'];
		$right_id = $q['right_id'];
		$question = $q['question'];
		$type = $q['type'];
		$required = $q['required'];

		// If there is a question to the left, update it's right pointer
		if ($left_id > 0)
		{
			$db->sql_return_on_error(true);
			$sql = 'UPDATE ' . APPLYS_QUESTIONS_TABLE . "
				SET right_id = '" . (int)$right_id . "'
				WHERE question_id = '" . (int)$left_id . "'";
			$result = $db->sql_query($sql);

			$db->sql_freeresult($result);
			$db->sql_return_on_error(false);
		}

		// If there is a question to the right, update it's left pointer
		if ($right_id > 0)
		{
			$db->sql_return_on_error(true);
			$sql = 'UPDATE ' . APPLYS_QUESTIONS_TABLE . "
				SET left_id = '" . (int)$left_id . "'
				WHERE question_id = '" . (int)$right_id . "'";
			$result = $db->sql_query($sql);

			$db->sql_freeresult($result);
			$db->sql_return_on_error(false);
		}

		// Delete this question from the database
		$db->sql_return_on_error(true);
		$sql = 'delete from ' . APPLYS_QUESTIONS_TABLE . "
			WHERE question_id = '" . (int)$qid . "'";
		$result = $db->sql_query($sql);

		$db->sql_freeresult($result);
		$db->sql_return_on_error(false);

		// If it is the first question, update that pointer
		if ($this->applys_config['first_question_id'] == $qid)
		{
			$this->set_applys_config('first_question_id', $right_id);
		}

		// If it is the last question, update that pointer
		if ($this->applys_config['last_question_id'] == $qid)
		{
			$this->set_applys_config('last_question_id', $left_id);
		}
	}

	/**
	* Move question up in database
	* This does not update $this->applys_questions
	* qid = question_id
	*/
	function moveup_question($qid)
	{
		global $db;

		if (!$qid)
		{
			trigger_error("Invalid question_id to moveup_question");
		}

		if (!isset($this->applys_questions[$qid]))
		{
			trigger_error("Call to moveup_question with non-existent question.");
		}

		$q = $this->applys_questions[$qid];
		$left_id = $q['left_id'];
		$right_id = $q['right_id'];
		$question = $q['question'];
		$type = $q['type'];
		$required = $q['required'];

		if (!$left_id)
		{
			trigger_error("Call to moveup_question for the top question.");
			// return;
		}

		$left_q = $this->applys_questions[$left_id];
		if (!isset($left_q))
		{
			trigger_error("moveup_question could not find left question, left_id:" . $left_id);
		}
		$left_left_id = $left_q['left_id'];
		if (!isset($left_left_id))
		{
			trigger_error("moveup_question could not find left question's left_id.");
		}

		// If there is a left_left_id, need to update it's right point
		if ($left_left_id > 0)
		{
			$db->sql_return_on_error(true);
			$sql = 'UPDATE ' . APPLYS_QUESTIONS_TABLE . "
				SET right_id = '" . (int)$qid . "'
				WHERE question_id = '" . (int)$left_left_id . "'";
			$result = $db->sql_query($sql);

			$db->sql_freeresult($result);
			$db->sql_return_on_error(false);
		}

		// If there is a question to the left, update it's pointers
		if ($left_id > 0)
		{
			$db->sql_return_on_error(true);
			$sql = 'UPDATE ' . APPLYS_QUESTIONS_TABLE . "
				SET left_id = '" . (int)$qid . "',
				right_id = '" . (int)$right_id . "'
				WHERE question_id = '" . (int)$left_id . "'";
			$result = $db->sql_query($sql);

			$db->sql_freeresult($result);
			$db->sql_return_on_error(false);
		}

		// If there is a question to the right, update it's left pointer
		if ($right_id > 0)
		{
			$db->sql_return_on_error(true);
			$sql = 'UPDATE ' . APPLYS_QUESTIONS_TABLE . "
				SET left_id = '" . (int)$left_id . "'
				WHERE question_id = '" . (int)$right_id . "'";
			$result = $db->sql_query($sql);

			$db->sql_freeresult($result);
			$db->sql_return_on_error(false);
		}

		// Update both pointers for question
		$db->sql_return_on_error(true);
		$sql = 'UPDATE ' . APPLYS_QUESTIONS_TABLE . "
			SET left_id = '" . (int)$left_left_id . "',
			right_id = '" . (int)$left_id . "'
			WHERE question_id = '" . (int)$qid . "'";
		$result = $db->sql_query($sql);

		$db->sql_freeresult($result);
		$db->sql_return_on_error(false);

		// If it is now first question, update that pointer
		if ($this->applys_config['first_question_id'] == $left_id)
		{
			$this->set_applys_config('first_question_id', $qid);
		}

		// If it was the last question, update that pointer
		if ($this->applys_config['last_question_id'] == $qid)
		{
			$this->set_applys_config('last_question_id', $left_id);
		}
	}

	/**
	* Move question down in database
	* This does not update $this->applys_questions
	* qid = question_id
	*/
	function movedown_question($qid)
	{
		if (!$qid)
		{
			trigger_error("Invalid question_id to movedown_question");
		}

		if (!isset($this->applys_questions[$qid]))
		{
			trigger_error("Call to movedown_question with non-existent question.");
		}

		$q = $this->applys_questions[$qid];
		$left_id = $q['left_id'];
		$right_id = $q['right_id'];
		$question = $q['question'];
		$type = $q['type'];
		$required = $q['required'];

		if (!$right_id)
		{
			trigger_error("Call to movedown_question for the last question.");
			// return;
		}

		// Moving question down is the same as moving the question after it up
		// Why duplicate code
		$this->moveup_question($right_id);
	}

	/**
	* Select Faction
	*/
	function select_faction($selected_value, $key)
	{
		global $user;

		$faction_type_ary = array('APPLYS_HORDE', 'APPLYS_ALLIANCE');
		$faction_options = '';
		foreach ($faction_type_ary as $faction_type)
		{
			$selected = ($selected_value == $user->lang($faction_type)) ? ' selected="selected"' : '';
			$faction_options .= '<option value="' . $user->lang($faction_type) . '"' . $selected . '>' . $user->lang[$faction_type] . '</option>';
		}

		return $faction_options;
	}

	/**
	* Select Region
	*/
	function select_region($selected_value, $key)
	{
		global $user;

		$region_ary = array('US', 'EU', 'TW', 'CN', 'KR');
		$region_options = '';
		foreach ($region_ary as $region)
		{
			$selected = ($selected_value == $region) ? ' selected="selected"' : '';
			$region_options .= '<option value="' . $region . '"' . $selected . '>' . $region . '</option>';
		}

		return $region_options;
	}

	/**
	* Select user
	*/
	function select_user($selected_value, $key)
	{
		global $user, $phpbb_root_path, $phpEx;

		$url = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=searchuser&amp;form=acp_applys&amp;field=' . $key . '&amp;select_single=true');
		return '<input class="text medium" type="text" size="40" id="'. $key . '" name="config[' . $key . ']" value="' . $selected_value . '" /> ' . '&nbsp;&nbsp;[ <a href="' . $url . '" onclick="find_username(this.href); return false;">' . $user->lang('FIND_USERNAME') . '</a> ]';
	}

	/**
	* Check a user_id's plain text password
	*/
	function check_password($user_id, $password)
	{
		global $db;

		$sql = 'SELECT *
			FROM ' . USERS_TABLE . ' u
			WHERE user_id = ' . (int)$user_id;
		$result = $db->sql_query_limit($sql, 1);
		$user_row = $db->sql_fetchrow($result);
		$db->sql_freeresult($result);

		if (!user_row)
		{
			return false;
		}

		if (phpbb_check_hash($password, $user_row['user_password'])) {
			return true;
		}
		return false;
	}

	/**
	* Select a forum
	*/
	function select_forum($selected_value, $key = '')
	{
		// select_id = $selected_value
		// ignore_id = false
		// ignore_acl = true
		// ignore_nonpost = false
		// ignore_emptycat = false
		// only_acl_post = false
		// return_array = false
		return make_forum_select($selected_value, false, true, true, true, false, false);
	}

	/**
	* Get Question type
	*/
	function get_qtype($type_id)
	{
		global $user;

		$type = '';
		switch ($type_id)
		{
			case 1:
				$type = $user->lang('APPLYS_QTYPE_SECTION');
				break;
			case 2:
				$type = $user->lang('APPLYS_QTYPE_STATEMENT');
				break;
			case 3:
				$type = $user->lang('APPLYS_QTYPE_TEXT');
				break;
			case 4:
				$type = $user->lang('APPLYS_QTYPE_TEXTAREA');
				break;
			case 5:
				$type = $user->lang('APPLYS_QTYPE_YESNO');
				break;
			case 6:
				$type = $user->lang('APPLYS_QTYPE_RACE');
				break;
			case 7:
				$type = $user->lang('APPLYS_QTYPE_CLASS');
				break;
			case 8:
				$type = $user->lang('APPLYS_QTYPE_PROFESSION');
				break;
			case 9:
				$type = $user->lang('APPLYS_QTYPE_PRIVATE');
				break;
			case 10:
				$type = $user->lang('APPLYS_QTYPE_TZ');
				break;
			case 11:
				$type = $user->lang('APPLYS_QTYPE_SKILL');
				break;
			case 12:
				$type = $user->lang('APPLYS_QTYPE_DAYSPERWEEK');
				break;
			case 13:
				$type = $user->lang('APPLYS_QTYPE_ROLE');
				break;
			case 14:
				$type = $user->lang('APPLYS_QTYPE_SELECTDAYS');
				break;
			case 15:
				$type = $user->lang('APPLYS_QTYPE_CHARACTER');
				break;
			case 16:
				$type = $user->lang('APPLYS_QTYPE_REALM');
				break;
		}
		return $type;
	}

	/**
	* Select Question type
	*/
	function select_qtype($selected_value, $key = '')
	{
		// trigger_error("selected_value: " . $selected_value);
		$faction_options = '';
		for ($i = 1; $i <= $this->NUM_QTYPES; $i++)
		{
			$type = $this->get_qtype($i);
			$selected = ($selected_value == $i) ? ' selected="selected"' : '';
			$faction_options .= '<option value="' . $i . '"' . $selected . '>' . $type . '</option>';
		}
		return $faction_options;
	}

	/**
	* Select control buttons
	*/
	function select_control($selected_value, $key)
	{
		global $user, $phpbb_root_path, $phpEx;

		// key = "question_control" . $question_id;
		$delete_name = preg_replace('/question_control(\d+)/', 'delete[${1}]', $key);
		$moveup_name = preg_replace('/question_control(\d+)/', 'moveup[${1}]', $key);
		$movedown_name = preg_replace('/question_control(\d+)/', 'movedown[${1}]', $key);
		$qid = preg_replace('/question_control(\d+)/', '${1}', $key);

		$buttons = '<input class="button1" type="submit" id="' . $delete_name .'" name="'. $delete_name .'" value="'. $user->lang('APPLYS_DELETE') .'" />&nbsp;';

		if (isset($this->applys_config['first_question_id']) and
		    ($this->applys_config['first_question_id'] !== $qid))
		{
			$buttons .= '<input class="button1" type="submit" id="' . $moveup_name .'" name="'. $moveup_name .'" value="'. $user->lang('APPLYS_MOVEUP') .'" />&nbsp;';
		}

		if (isset($this->applys_config['last_question_id']) and
		    ($this->applys_config['last_question_id'] !== $qid))
		{
			$buttons .= '<input class="button1" type="submit" id="' . $movedown_name .'" name="'. $movedown_name .'" value="'. $user->lang('APPLYS_MOVEDOWN') .'" />&nbsp;';
		}

		$buttons .= '<BR><HR style="height: 10px; solid;">';
		return $buttons;
	}
}

?>
